package simu

import (
	"fmt"
	"strings"
	"topobuild/base"
)

type SimuKeeper struct {
	DevIdMap     map[string]int
	tb_Device    []TableDevice
	DevIntfIdMap map[string]int // devid-ethName : index
	tb_Intface   []TableIntface
	tb_Links     []TableLink
}

func NewSimuKeeper() *SimuKeeper {
	return &SimuKeeper{}
}

func (sk *SimuKeeper) Table_Device() []TableDevice {
	return sk.tb_Device
}

func (sk *SimuKeeper) Table_Intface() []TableIntface {
	return sk.tb_Intface
}

func (sk *SimuKeeper) Table_Link() []TableLink {
	return sk.tb_Links
}

func (sk *SimuKeeper) ShowDevInfo(devName string, conf *base.Config) {
	info := ""
	info += fmt.Sprintf("设备名称: %s\n", devName)
	info += fmt.Sprintf("设备ID: %d\n", sk.DevIdMap[devName])
	for _, aa := range conf.AsAreas {
		for _, dia := range aa.DevInAs {
			if dia.Dev == devName {
				info += fmt.Sprintf("AS: %d\n", aa.As)
				for _, id := range dia.Intfs {
					// 对端设备和端口信息
					peerDev, peerIp := conf.FindPeerDev(devName, id.Port, id.PortIp)
					if peerDev == "" && peerIp == "" {
						info += fmt.Sprintf("=> Port & IP : %s , %s\n", id.Port, id.PortIp)
					} else {
						peerPort := conf.FindDevIntf(peerDev, peerIp)
						info += fmt.Sprintf("=> Port & IP : %s , %s\n", id.Port, id.PortIp)
						peerLoopback0Ip := conf.GetDevLoopBack0Ip(peerDev)
						info += fmt.Sprintf("   Peer AS%d : %s , %s , %s , %s\n", conf.GetDevAs(peerDev), peerDev, peerPort, peerIp, peerLoopback0Ip)
					}
				}
				break
			}
		}
	}
	fmt.Printf("info: %v\n", info)
}

func (sk *SimuKeeper) GenTableLink(conf *base.Config, outfile string) {

	getDevIdIntfIndex := func(devName, ethIp string) (int, int) {
		for _, aa := range conf.AsAreas {
			for _, dia := range aa.DevInAs {
				if dia.Dev == devName {
					for _, id := range dia.Intfs {
						if id.PortIp == ethIp {
							devid := sk.DevIdMap[devName]
							key := fmt.Sprintf("%d-%s", devid, id.Port)
							intfid := sk.DevIntfIdMap[key]
							return devid, intfid
						}
					}
				}
			}
		}
		return -1, -1
	}

	tbLinks := make([]TableLink, 0)
	for _, l := range conf.Links {
		p1Dev, p1Ip := getDevIdIntfIndex(l.Peer1.Dev, l.Peer1.PortIp)
		p2Dev, p2Ip := getDevIdIntfIndex(l.Peer2.Dev, l.Peer2.PortIp)
		if p1Dev == -1 || p2Dev == -1 || p1Ip == -1 || p2Ip == -1 {
			panic(fmt.Sprintf("can't find devId or intfId for %s-%s", l.Peer1.Dev, l.Peer1.PortIp))
		}
		tlk := &TableLink{
			RsingId:      1,
			LeftDevId:    p1Dev,
			LeftIfIndex:  p1Ip,
			ToRsingId:    1,
			RightDevId:   p2Dev,
			RightIfIndex: p2Ip,
			LinkIfSpeed:  10000000000,
		}
		tbLinks = append(tbLinks, *tlk)
	}

	sk.tb_Links = tbLinks
	WriteLinkXlsx(outfile, tbLinks)
}

func (sk *SimuKeeper) GenTableIntface(conf *base.Config, outfile string) {

	completeSubfix := func(ip string) string {
		if strings.HasSuffix(ip, "/24") {
			return ip
		} else {
			return ip + "/24"
		}
	}

	devIntfIdMap := make(map[string]int)
	var intfs []TableIntface
	for _, aa := range conf.AsAreas {
		for _, dia := range aa.DevInAs {
			devName := dia.Dev
			for i3, id := range dia.Intfs {
				devid := sk.DevIdMap[devName]
				tintf := &TableIntface{
					RsingId:     1,
					DevId:       devid,
					IfIndex:     i3 + 1,
					DisplayName: id.Port,
					IfSpeed:     10000000000,
					IpAddress:   completeSubfix(id.PortIp),
					Ipv6Address: "",
				}
				key := fmt.Sprintf("%d-%s", devid, id.Port)
				devIntfIdMap[key] = i3 + 1
				intfs = append(intfs, *tintf)
			}
		}
	}

	sk.DevIntfIdMap = devIntfIdMap
	sk.tb_Intface = intfs
	WriteIntfaceXlsx(outfile, intfs)
}

func (sk *SimuKeeper) GenTableDevice(conf *base.Config, outfile string) {
	devs := make([]TableDevice, 0)
	devIdMap := make(map[string]int)
	id := 1
	for _, aa := range conf.AsAreas {
		// asNum := aa.As
		for _, dia := range aa.DevInAs {
			// 获取设备id
			devid := id
			devName := dia.Dev
			if devIdMap[devName] > 0 {
				devid = devIdMap[devName]
			} else {
				devIdMap[devName] = devid
				id++
			}
			// 转换成TableDevice
			var tdev *TableDevice = nil
			for _, id := range dia.Intfs {
				if id.Port == "loopback" {
					tdev = &TableDevice{
						RsingId:  1,
						DevId:    devid,
						DevIp:    id.PortIp,
						DevName:  devName,
						City:     "北京",
						Province: "北京",
						DevType:  "核心节点",
					}
					break
				}
			}
			if tdev == nil {
				for _, id := range dia.Intfs {
					// ip.Port contains the "loopback" str
					if strings.Contains(id.Port, "loopback") {
						tdev = &TableDevice{
							RsingId:  1,
							DevId:    devid,
							DevIp:    id.PortIp,
							DevName:  devName,
							City:     "北京",
							Province: "北京",
							DevType:  "一般节点",
						}
						break
					}
				}
			}
			devs = append(devs, *tdev)
		}
	}

	// 保存一些必要的信息
	sk.DevIdMap = devIdMap
	sk.tb_Device = devs

	// 输出到表格文件
	WriteDevXlsx(outfile, devs)
}
